package com.je.core.lock;

import com.je.core.exception.PlatformException;
import com.je.core.exception.PlatformExceptionEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Redis分布式锁注解解析器
 *
 * @author wangmm@ketr.com.cn
 * @date 2020/12/16
 */
@Aspect
@Component
@Slf4j
public class DistributedLockHandler {

    @Autowired
    RedisSingleLock redisSingleLock;

    @Around("@annotation(lock)")
    public void around(ProceedingJoinPoint joinPoint, DistributedLock lock) throws Throwable {
        //生成锁key
        String key = lock.value();
        if (StringUtils.isBlank(key)) {
            //默认为包名+类名+方法名
            key = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        }
        //生成唯一value
        String value = Thread.currentThread().getName() + System.currentTimeMillis();

        try {
            //开始加锁
            log.info("tryLock [{}] [{}]", key, value);
            Boolean locked = redisSingleLock.tryLock(
                    key, value,
                    lock.unit().toMillis(lock.timeout()),
                    lock.retries(),
                    lock.unit().toMillis(lock.waitingTime()));
            log.info("lock {} [{}] [{}]", locked ? "success" : "fail", key, value);
            if (locked) {
                //加锁成功获取执行业务
                joinPoint.proceed();
            } else {
                throw new PlatformException("Lock fail [" + key + "]", PlatformExceptionEnum.UNKOWN_ERROR);
            }
        } finally {
            //释放该锁
            Boolean b = redisSingleLock.unLock(key, value);
            log.info("unlock {} [{}] [{}]", b ? "success" : "fail", key, value);
        }
    }

}
